package com.han.demo.transaction;

import com.han.demo.entity.User;
import com.han.demo.mapper.UserMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

/**
 * @author hanjl
 * @Description 如果当前事务存在，则在嵌套事务中执行，否则REQUIRED的操作一样（开启一个事务）
 * @ClassName Nested
 * @createTime 2021/11/18 17:40
 */
@Service
public class Nested {
    /*
    和REQUIRES_NEW的区别
        REQUIRES_NEW是新建一个事务并且新开启的这个事务与原有事务无关，而NESTED则是当前存在事务时（我们把当前事务称之为父事务）会开启一个嵌套事务（称之为一个子事务）。
        在NESTED情况下父事务回滚时，子事务也会回滚，而在REQUIRES_NEW情况下，原有事务回滚，不会影响新开启的事务。
    和REQUIRED的区别
        REQUIRED情况下，调用方存在事务时，则被调用方和调用方使用同一事务，那么被调用方出现异常时，由于共用一个事务，所以无论调用方是否catch其异常，事务都会回滚
        而在NESTED情况下，被调用方发生异常时，调用方可以catch其异常，这样只有子事务回滚，父事务不受影响
     */
    @Resource
    private UserMapper userMapper;
    /**
     * 加上@Transactional注解会生成Mandatory的代理对象，如果不用生成的代理对象去调用testB
     * 则事务的传播规则会失效。因为不用代理对象去调用，就还是没有加事务的普通对象去调用的，事务的传播机制就会失效
     */
    @Resource
    private Nested nested;

    @Transactional(propagation = Propagation.REQUIRED)
    public void testMain(){
        User a = new User();
        a.setName("required");
        A(a);
        testB();
        if(true){
            throw new NullPointerException();
        }
    }
    @Transactional(propagation = Propagation.REQUIRED)
    public void testB(){
        User b = new User();
        b.setName("required2");
        B(b);

        User b2 = new User();
        b2.setName("required3");
        B(b2);
    }

    public void A(User user){
        userMapper.insert(user);
    }

    public void B(User user){
        userMapper.insert(user);
    }
}
